#include "lib/epoll_mgr.hpp"
using namespace std;

epoll_mgr::epoll_mgr(server* s) {
  if ((s_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
    perror("Couldn't create socket!");
    exit(1);
  }
  
  server_addr.sin_family = AF_INET;
  server_addr.sin_port = htons(PORT);
  server_addr.sin_addr.s_addr = INADDR_ANY;
  memset(&server_addr, 0, sizeof(server_addr));
  
  if (bind(s_sock, (sockaddr*)&server_addr, sizeof(server_addr)) == -1) {
    perror ("Bind to socket failed");
    exit(1);
  }
  
  if ((epoll_fd = epoll_create(MAX_CLIENTS)) == -1) {
    perror ("Epoll creation failed!");
    exit(1);
  }
  
  ev.events = EPOLLIN;
  ev.data.fd = s_sock;
  
  if (epoll_ctl (epoll_fd, EPOLL_CTL_ADD, s_sock, &ev) < 0) {
    perror ("Server sock not added to epoll");
    exit(1);
  }
  client_count = 0;
  this->s = s;
}

epoll_mgr::~epoll_mgr() {
}

void epoll_mgr::add_sock_to_epoll(int sock) {
  if(epoll_ctl (epoll_fd, EPOLL_CTL_ADD, sock, &ev) < 0) {
    perror ("couldn't add socket");
  }
}

void epoll_mgr::remove_sock(int sock) {
  if(epoll_ctl (epoll_fd, EPOLL_CTL_DEL, sock, &ev) < 0) {
    perror ("couldn't add socket");
  }
}

void epoll_mgr::event_loop() {
  for(;;) {
    res = epoll_wait (epoll_fd, events, MAX_CLIENTS, -1);
    if (res == -1) {
      perror ("Error in epoll_wait");
      exit(1);
    }
    for (int i = 0; i < res; ++1) {
      if (events[i].data.fd == s_sock) {
        clients[client_count] = accept(s_sock,
                                       (*sockaddr) client_addr,
                                       sizeof(client_addr));
        ev.events = EPOLLIN | EPOLLOUT;
        ev.data.fd = clients[client_count];
        this->add_sock_to_epoll (clients[client_count]);
        break;
      } else {
        if (events[i].events & EPOLLHUP) {
          this->remove_sock(events[i].data.fd);
          close(events[i].data.fd);
          break;
        } 
        
        if (events[i].events & EPOLLIN) {
          s->handle_data(events[i].data.fd);
          break;
        }
          
        if (events[i].events & EPOLLOUT) {
          s->send_data(events[i].data.fd);
          break;
        }
      }
    }
  }
}

